﻿/**************************************************************
 *
 * 唯一标识：640f1d85-7767-4344-be7d-ec22c9b194b8
 * 命名空间：Xunit.Sgr.Cap
 * 创建时间：2024/7/22 16:36:14
 * 机器名称：DESKTOP-HJ4OAG9
 * 创建者：CocoYuan
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using DotNetCore.CAP;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Savorboard.CAP.InMemoryMessageQueue;
using Sgr.Data;
using Sgr.EntityFrameworkCore;
using Sgr.MediatR.Behaviors;
using Sgr.Trackers;
using Sgr.Utilities;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using Xunit.Abstractions;
using Xunit.Sdk;
using Xunit.Sgr.Cap.HelperClass;
using static System.Formats.Asn1.AsnWriter;

namespace Xunit.Sgr.Cap
{
    public abstract class CapTestBase : IDisposable
    {
        public const string TestGroupName = "Test";

        protected readonly ServiceProvider _serviceProvider;
        protected readonly ICapPublisher _publisher;

        protected readonly ObservableMessage _observable = new ObservableMessage();

        protected CapTestBase(ITestOutputHelper testOutput)
        {
            var services = new ServiceCollection();

            IConfiguration configuration = CreateConfiguration();
            services.AddSingleton(configuration);

            services.AddSingleton(sp => new MessageCollector(_observable));

            services.AddLogging(x => x.AddProvider(new TestLoggingProvider(testOutput)));
            services.AddSgrCore();
            services.UseRedis();

            AddData(services);
            AddCap(services, configuration);

            services.AddMediatR(cfg =>
            {
                cfg.RegisterServicesFromAssemblyContaining(typeof(CapTestBase));
#if DEBUG
                cfg.AddOpenBehavior(typeof(LoggingBehavior<,>));
#endif
                cfg.AddOpenBehavior(typeof(ValidatorBehavior<,>));
                cfg.AddOpenBehavior(typeof(TransactionBehavior<,>));
            });

            ConfigureServices(services);

            _serviceProvider = services.BuildServiceProvider();
            _publisher = _serviceProvider.GetRequiredService<ICapPublisher>();

            AsyncHelper.RunSync(() => _serviceProvider.GetRequiredService<IBootstrapper>().BootstrapAsync());
        }

        private IConfiguration CreateConfiguration()
        {
            return new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddEnvironmentVariables()
                .AddJsonFile("appsettings.json")
                .Build();
        }

        protected virtual void AddData(ServiceCollection services)
        {
            services.AddSingleton<IDataConnectionStringProvider, TestDataConnectionStringProvider>();
            services.AddSgrEntityFrameworkCore();

            ILoggerFactory myLoggerFactory = LoggerFactory.Create(builder => builder.AddDebug());
            services.UseMySql("TEST", (builder) =>
            {
                builder
                    .MinBatchSize(1)
                    .MaxBatchSize(1000);

                //sqlOptions.CharSet(CharSet.Utf8);
                //sqlOptions.MigrationsAssembly(typeof(Program).Assembly.FullName);
                //// Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
                //sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
            }, myLoggerFactory);
        }

        protected virtual void AddCap(IServiceCollection services, IConfiguration configuration)
        {
            services.AddCap(x =>
            {
                x.DefaultGroupName = TestGroupName;
                x.UseInMemoryStorage();
                x.UseInMemoryMessageQueue();
            });
        }

        protected virtual void ConfigureServices(IServiceCollection services)
        { }

        public virtual void Dispose()
        {
            _serviceProvider.Dispose();
        }
    }
}